#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include "drawing.hpp"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"
#include <cstdlib>
#include <algorithm> 
#include <iostream>
#include "common/common_utils.h"
#include <cstring>
#include <cmath>
#include "ingenic_mnni.h"
#include "utils/imgproc.h"
#include "utils/postproc.h"
#include "data_type.h"
#include "recog_interface.h"
#include "xb_image_utils.h"
#include "yolo_interface.h"

#define IS_ALIGN_64(x) (((size_t)x) & 0x3F)
static const uint8_t color[3] = {0xff, 0, 0};

namespace Recog{
    RecogInterface::RecogInterface(RecogConfig config) {
        this->recog_config = config;
    }

    int RecogInterface::releaseModel() {
        if (this->model != nullptr) {
            magik_destroy_model(this->model);
            this->model = nullptr;
        }
        printf("magik_destroy_model: %s release over\n", recog_config.model_path.c_str());
        return 0;
    }

    int RecogInterface::loadModel() {
        int model_num = 0;
        Network **derived_models;
        if (magik_load_model(derived_models, model_num, recog_config.model_path.c_str())) {
            printf("create model failed.\n");
            return -1;
        }
        this->model = derived_models[0];
        printf("magik model loaded.\n");
        return 0;
    }

    void RecogInterface::print_model_forward_memory() {
        if (this->model == nullptr) {
            printf("model is null\n");
            return;
        }
        int ret = this->model->get_forward_memory_size();
        std::cout << "model forward memory size: " << ret << " = " << ret / 1024 << "KB" << " = " << ret / 1024 / 1024 << "MB" << std::endl;
    }

    float RecogInterface::L2_distance(const std::vector<float>& a, const std::vector<float>& b) {
        // 使用 std::inner_product 计算平方差和
        float sum = std::inner_product(
            a.begin(), a.end(), b.begin(), 0.0f,
            std::plus<float>(),
            [](float x, float y) { float d = x - y; return d * d; }
        );

        return std::sqrt(sum);
    }

    double RecogInterface::reduceL2(const float* input, int size_) {
        double squaredSum = 0.0;
        for (int i = 0; i< size_; ++i) {
            squaredSum += input[i] * input[i];
        }
        double l2Norm = std::sqrt(squaredSum);
        return l2Norm;
    }

    void RecogInterface::run_model(
        magik::uranus::Tensor &img,
        std::vector<float> &out  // 改为引用传递
    ) {

        int img_size = img.get_bytes_size();
        auto input_names = model->get_input_names();
        // printf("input_names: %s\n", input_names[0].c_str());
        for (auto n : input_names) {
            auto input = model->get_input(n);
            uint8_t *indata = (uint8_t*)(input.vdata<uint8_t>());
            memcpy((void *)indata, (void *)img.vdata<uint8_t>(), img_size * sizeof(uint8_t));

            // 前向推理
            int RUN_CNT = 1;
            for (int i = 0; i < RUN_CNT; i++) {
                model->run();
            }

            // 获取输出
            auto output_names = model->get_output_names();
            for (auto n : output_names) {
                // std::cout << "output_names: " << n << std::endl;
                auto output = model->get_output(n);
                const float* r_ptr1 = output.vdata<float>();
                double l2_data = reduceL2(r_ptr1, recog_config.size);

                // 将结果写入 out（引用传递，外部可见）
                for (int i = 0; i < recog_config.size; ++i) {
                    out[i] = r_ptr1[i] / l2_data;
                }
                auto shape = output.shape();
                // std::cout<<"mobileNet output_shape: "<< shape[0] << " " <<std::endl;
            }
        }
    }

    void RecogInterface::registerCat(magik::uranus::Tensor &recog_working_img, RegisterInfo &register_info, std::string name, std::string id) {
        std::vector<float> register_feat(recog_config.size);
        run_model(recog_working_img, register_feat);
        register_info.feat = register_feat;
        register_info.name = name;
        register_info.id = id;
    }

    void RecogInterface::recognizeCat(magik::uranus::Tensor &recog_working_img, std::vector<RecognizeInfo> &recognize_infos, std::vector<RegisterInfo> &register_infos){
        if (register_infos.empty()) {
            return;
        }
        recognize_infos.clear();
        std::vector<float> recog_feat(recog_config.size);
        run_model(recog_working_img, recog_feat);
        for (auto &register_info : register_infos) {
            float distance = L2_distance(register_info.feat, recog_feat);
            RecognizeInfo recognize_info;
            recognize_info.id = register_info.id;
            recognize_info.name = register_info.name;
            recognize_info.distance = distance;
            recognize_info.is_match = distance < recog_config.dist_thres;
            recognize_infos.push_back(recognize_info);
        }
    }

    void RecogInterface::printRegisterInfo(std::vector<RegisterInfo> &register_infos) {
        for (auto &register_info : register_infos) {
            printf("register_info \n");
            printf("------------- \n");
            printf("id: %s, name: %s, feat_size: %d\n", register_info.id.c_str(), register_info.name.c_str(), register_info.feat.size());
        }
    }
    void RecogInterface::printRecognizeResults(std::vector<RecognizeInfo> &recognize_results) {
        for (auto &recognize_result : recognize_results) {
            printf("recognize_result \n");
            printf("------------- \n");
            printf("id: %s, name: %s, distance: %f, is_match: %d\n", recognize_result.id.c_str(), recognize_result.name.c_str(), recognize_result.distance, recognize_result.is_match);
            if(recognize_result.is_match) {
                printf("Final Result: \n");
                printf("id: %s, name: %s, distance: %f, is_match: %d\n", recognize_result.id.c_str(), recognize_result.name.c_str(), recognize_result.distance, recognize_result.is_match);
                printf("\n");
            }
        }
    }
}
namespace Detect{
    YOLOV5Interface::YOLOV5Interface(YOLOV5Config config) {
        yolo5_config = config;
    }
    
    int YOLOV5Interface::releaseModel() {
        if (this->model != nullptr) {
            magik_destroy_model(this->model);
            this->model = nullptr;
        }
        printf("magik_destroy_model: %s release over\n", yolo5_config.model_path.c_str());
        return 0;
    }
    
    int YOLOV5Interface::loadModel() {
        int model_num = 0;
        Network **derived_models;
        if (magik_load_model(derived_models, model_num, yolo5_config.model_path.c_str())) {
            printf("create model failed.\n");
            return -1;
        }
        this->model = derived_models[0];
        printf("magik model_path %s model loaded.\n", yolo5_config.model_path.c_str());
        return 0;
    }
    
    void YOLOV5Interface::print_model_forward_memory() {
        if (this->model == nullptr) {
            printf("model is null\n");
            return;
        }
        int ret = this->model->get_forward_memory_size();
        std::cout << "model: " << yolo5_config.model_path << " forward memory size: " << ret << " = " << ret / 1024 << "KB" << " = " << ret / 1024 / 1024 << "MB" << std::endl;
    }
    
    void YOLOV5Interface::genBBox(std::vector<Tensor> out_res, 
        std::vector<ObjBbox_t>& candidate_boxes, 
        int img_w, 
        int img_h) {
        generate_box(out_res, this->strides, this->anchor, candidate_boxes, img_w, img_h, yolo5_config.classes, yolo5_config.box_num, yolo5_config.conf_thresh, detector_type);
    }
     
    void YOLOV5Interface::run_model(Network *model, Tensor &img, std::vector<Tensor> &outputs) {
        int img_size = img.get_bytes_size();
        auto input_names = model->get_input_names();
        for(auto n: input_names) {
            // std::cout<<"input_names: "<< n <<std::endl;
            auto input = model->get_input(n);
            auto shape = input.shape();
            // std::cout<<"input_shape: "<< shape[0] << " " << shape[1] << " " << shape[2] << " " << shape[3] << " " <<std::endl;
    
            uint8_t *indata = (uint8_t*)(input.vdata<uint8_t>());
            memcpy((void *)indata, (void *)img.vdata<uint8_t>(), img_size * sizeof(uint8_t));
    
            // const unsigned char* in_ptr = input.vdata<uint8_t>();
            // FILE *fp = fopen(std::string(n+".res").c_str(), "wb");
            // if (fp) {
            //     fwrite(in_ptr, 1, (input.get_bytes_size()), fp);
            //     fclose(fp);
            // } else {
            //     printf("open %s file failed\n", std::string(n+".res").c_str());
            //     return;
            // }
        }
    
        // net forword
        int RUN_CNT = 1;
        for (int i = 0; i < RUN_CNT; i++) {
            model->run();
        }
    
        // get outputs
        auto output_names = model->get_output_names();
        for(auto n: output_names) {
            // std::cout<<"output_names: "<< n <<std::endl;
            auto output = model->get_output(n);
            auto shape = output.shape();
            // std::cout<<"output_shape: "<< shape[0] << " " << shape[1] << " " << shape[2] << " " << shape[3] << " " <<std::endl;
    
            outputs.push_back(output);
    
            // const unsigned char* out_ptr = output.vdata<uint8_t>();
            // FILE *fp = fopen(std::string(n+".res").c_str(), "wb");
            // if (fp) {
            //     fwrite(out_ptr, 1, (output.get_bytes_size()), fp);
            //     fclose(fp);
            // } else {
            //     printf("open %s file failed\n", std::string(n+".res").c_str());
            //     return;
            // }
        }
    
        return;
    }
    
    void YOLOV5Interface::detect(magik::uranus::Tensor working_img, int orgin_width, int orgin_height, vector<ObjBbox_t>& output_boxes){
        /******************model forward***********************/
        std::vector<magik::uranus::Tensor> outputs;
        run_model(model, working_img, outputs); 
        working_img.free_data();
        /******************postprocess***********************/
        std::vector<magik::uranus::ObjBbox_t> temp_boxes;
        genBBox(outputs, temp_boxes, yolo5_config.input_w, yolo5_config.input_h);
        magik::uranus::nms(temp_boxes, output_boxes, yolo5_config.nms_thres, magik::uranus::NmsType_t::HARD_NMS);
        scale_boxes(orgin_width, orgin_height, yolo5_config.input_w, yolo5_config.input_h, output_boxes);
    }
     
    
    void YOLOV5Interface::scale_boxes(int ori_w, int ori_h, int new_w, int new_h, std::vector<magik::uranus::ObjBbox_t> &out_boxes) {
            float scale;
            float pad_x, pad_y;
            scale = std::min((float(new_w) / ori_w), (float(new_h) / ori_h));
            pad_x = (new_w - ori_w * scale) / 2;
            pad_y = (new_h - ori_h * scale) / 2;
            for (unsigned int i = 0; i < out_boxes.size(); i++)
            {
                out_boxes[i].box.x0 = round(std::max((out_boxes[i].box.x0 - pad_x) / scale, float(0)));
                out_boxes[i].box.x1 = round(std::min((out_boxes[i].box.x1 - pad_x) / scale, float(ori_w - 1)));
                out_boxes[i].box.y0 = round(std::max((out_boxes[i].box.y0 - pad_y) / scale, float(0)));
                out_boxes[i].box.y1 = round(std::min((out_boxes[i].box.y1 - pad_y) / scale, float(ori_h - 1)));
            }
        }
}
namespace XBUtils {
    int ImageUtils::fill_dim(uint8_t *data, int h, int w) {
        for (int i = 0; i < h*w; i++) {
            data[i*4+3] = 0;
        }
        return 0;
        }

    int ImageUtils::rgb2bgr(uint8_t *data, int data_cnt){
        uint8_t* p = data;
        int pixel_c = data_cnt / 4;
        for (int i=0; i < pixel_c; ++i) {
            uint8_t t = p[0];
            p[0] = p[2];
            p[2] = t;
            p += 4;
        }
        return 0;
    }

    int ImageUtils::read_img(FrameInfo &in, MyImg &img, const std::string &img_path) {
        printf("img_path===> %s\n", img_path.c_str());
        int ori_img_w = -1;
        int ori_img_h = -1;
        int comp = 0;
        unsigned char *imagedata = stbi_load(img_path.c_str(), &ori_img_w, &ori_img_h, &comp, 3); // image format is rgb
        if (!imagedata) {
            fprintf(stderr, "Error loading image: %s\n", img_path.c_str());
            return -1;
        }
        if(ori_img_w*ori_img_h > 2000*2000) {
            fprintf(stderr, "Image size %d * %d is too large, max size is 2000 * 1000\n", ori_img_w, ori_img_h);
            stbi_image_free(imagedata);
            return -1;
        }
        printf("Image loaded: width=%d, height=%d\n", ori_img_w, ori_img_h);
        img.w = ori_img_w;
        img.h = ori_img_h;
        img.c = comp;
        img.w_stride = ori_img_w * comp;
        img.data = imagedata;

        ori_img_w = -1;
        ori_img_h = -1;
        comp = 0;
        unsigned char *imagedata_info = stbi_load(img_path.c_str(), &ori_img_w, &ori_img_h, &comp, 4); // image format is rgb
        in.data = imagedata_info;
        in.width = ori_img_w;
        in.height = ori_img_h;
        fill_dim(in.data, ori_img_w, ori_img_h);
        printf("FrameInfo loaded: width=%d, height=%d\n", ori_img_w, ori_img_h);
        return 0;
    }

    int ImageUtils::img_to_frame(const MyImg &img, FrameInfo &frame) {
        // 检查输入有效性
        if (img.data == nullptr || img.w <= 0 || img.h <= 0 || img.c != 3) {
            fprintf(stderr, "Invalid MyImg input\n");
            return -1;
        }

        // 分配RGBA图像内存
        unsigned char *frame_data = (unsigned char *)malloc(img.w * img.h * 4);
        if (!frame_data) {
            fprintf(stderr, "Memory allocation failed\n");
            return -1;
        }

        // 从RGB转换为RGBA（Alpha通道设为255表示完全不透明）
        for (int i = 0; i < img.h; i++) {
            for (int j = 0; j < img.w; j++) {
                int src_idx = (i * img.w + j) * 3;  // RGB索引
                int dst_idx = (i * img.w + j) * 4;  // RGBA索引
                
                // 复制RGB通道，并设置Alpha通道
                frame_data[dst_idx + 0] = img.data[src_idx + 0]; // R
                frame_data[dst_idx + 1] = img.data[src_idx + 1]; // G
                frame_data[dst_idx + 2] = img.data[src_idx + 2]; // B
                frame_data[dst_idx + 3] = 255;                   // A (完全不透明)
            }
        }

        // 填充FrameInfo结构体
        frame.width = img.w;
        frame.height = img.h;
        frame.data = frame_data;

        return 0;
    }

    int ImageUtils::frame_to_img(const FrameInfo &frame, MyImg &img) {
        // 检查输入有效性
        if (frame.data == nullptr || frame.width <= 0 || frame.height <= 0) {
            fprintf(stderr, "Invalid FrameInfo input\n");
            return -1;
        }

        // 分配RGB图像内存
        unsigned char *imagedata = (unsigned char *)malloc(frame.width * frame.height * 3);
        if (!imagedata) {
            fprintf(stderr, "Memory allocation failed\n");
            return -1;
        }

        // 从RGBA转换为RGB
        for (int i = 0; i < frame.height; i++) {
            for (int j = 0; j < frame.width; j++) {
                int src_idx = (i * frame.width + j) * 4;  // RGBA索引
                int dst_idx = (i * frame.width + j) * 3;  // RGB索引
                
                // 复制RGB通道，忽略Alpha通道
                imagedata[dst_idx + 0] = frame.data[src_idx + 0]; // R
                imagedata[dst_idx + 1] = frame.data[src_idx + 1]; // G
                imagedata[dst_idx + 2] = frame.data[src_idx + 2]; // B
            }
        }

        // 填充Img结构体
        img.w = frame.width;
        img.h = frame.height;
        img.c = 3;
        img.w_stride = frame.width * 3;
        img.data = imagedata;

        return 0;
    }

    void ImageUtils::saveNV12ToJpeg(std::vector<uint8_t> data, int width, int height, std::string filename, int quality) {
        // nv12ToRgb(data.data(), width, height, rgb_data); // 先转 RGB
        // // 使用 stb 库保存为 JPEG
        // stbi_write_jpg(filename.c_str(), width, height, 3, rgb_data.data(), quality);
        // return;
    }


    // YUV 到 RGB 转换
    void ImageUtils::yuvToRGB(uint8_t y, uint8_t u, uint8_t v, RGB& out_rgb) {
        float y_f = y;
        float u_f = u - 128.0f;
        float v_f = v - 128.0f;
        
        float r = y_f + 1.402f * v_f;
        float g = y_f - 0.344136f * u_f - 0.714136f * v_f;
        float b = y_f + 1.772f * u_f;
        
        r = std::max(0.0f, std::min(255.0f, r));
        g = std::max(0.0f, std::min(255.0f, g));
        b = std::max(0.0f, std::min(255.0f, b));
        
        out_rgb.r = static_cast<uint8_t>(r);
        out_rgb.g = static_cast<uint8_t>(g);
        out_rgb.b = static_cast<uint8_t>(b);
    }


    // NV12 转 RGB 的函数
    void ImageUtils::nv12ToRgb(const uint8_t* nv12_data, int width, int height, uint8_t* rgb_data) {
        // const uint8_t* y_plane = nv12_data;
        // const uint8_t* uv_plane = nv12_data + width * height;
        
        // for (int y = 0; y < height; ++y) {
        //     for (int x = 0; x < width; ++x) {
        //         // Get YUV components
        //         int y_pos = y * width + x;
        //         int uv_pos = (y / 2) * (width / 2 + width % 2) + (x / 2);
                
        //         int Y = y_plane[y_pos];
        //         int U = uv_plane[uv_pos * 2] - 128;
        //         int V = uv_plane[uv_pos * 2 + 1] - 128;
                
        //         // YUV to RGB conversion formulas
        //         int R = clamp(Y + (int)(1.402 * V), 0, 255);
        //         int G = clamp(Y - (int)(0.344 * U) - (int)(0.714 * V), 0, 255);
        //         int B = clamp(Y + (int)(1.772 * U), 0, 255);
                
        //         // Write RGB values (assuming RGB24 format)
        //         int rgb_pos = (y * width + x) * 3;
        //         rgb_data[rgb_pos]     = static_cast<uint8_t>(R);
        //         rgb_data[rgb_pos + 1] = static_cast<uint8_t>(G);
        //         rgb_data[rgb_pos + 2] = static_cast<uint8_t>(B);
        //     }
        // }
    }


    void ImageUtils::read_nv12(FrameInfo &in, const std::string &img_path, int img_w, int img_h) {
        FILE *fp = NULL;
        int nv12_size = img_w * img_h * 1.5;
        uint8_t *nv12_data = (uint8_t *)malloc(nv12_size);
        fp = fopen(img_path.c_str(), "rb");
        if (fp) {
            int ret = fread(nv12_data, 1, nv12_size, fp);
            printf("\033[32mret %d\033[0m\n", ret);
            fclose(fp);
        } else {
            printf("open nv12 file failed\n");
            return;
        }
        in.data = nv12_data;
        in.width = img_w;
        in.height = img_h;
    }

    int ImageUtils::tensor_to_img(const magik::uranus::Tensor &tensor, MyImg &img) {
        // 检查Tensor有效性
        auto shape = tensor.shape();
        if (shape.size() != 4 || shape[0] != 1) {  // 假设Tensor格式为NHWC（1, H, W, C）
            fprintf(stderr, "Invalid tensor shape for image conversion\n");
            return -1;
        }
        int height = shape[1];
        int width = shape[2];
        int channels = shape[3];
        if (channels < 3) {  // 至少需要RGB三通道
            fprintf(stderr, "Tensor channel count must be >=3 for RGB conversion\n");
            return -1;
        }

        // 获取Tensor数据指针（假设是uint8_t类型）
        const uint8_t *tensor_data = tensor.vdata<uint8_t>();
        if (!tensor_data) {
            fprintf(stderr, "Tensor data pointer is null\n");
            return -1;
        }

        // 分配RGB图像内存（忽略Alpha通道）
        unsigned char *imagedata = (unsigned char *)malloc(width * height * 3);
        if (!imagedata) {
            fprintf(stderr, "Memory allocation failed for crop_img\n");
            return -1;
        }

        // 从Tensor（RGBA）转换为RGB
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int src_idx = (i * width + j) * channels;  // Tensor数据索引（RGBA）
                int dst_idx = (i * width + j) * 3;         // RGB目标索引
                
                // 复制RGB通道，忽略Alpha通道（如果存在）
                imagedata[dst_idx + 0] = tensor_data[src_idx + 0]; // R
                imagedata[dst_idx + 1] = tensor_data[src_idx + 1]; // G
                imagedata[dst_idx + 2] = tensor_data[src_idx + 2]; // B
            }
        }
        // 填充Img结构体
        img.w = width;
        img.h = height;
        img.c = 3;
        img.w_stride = width * 3;
        img.data = imagedata;

        return 0;
    }


    void ImageUtils::saveImg(MyImg &img, std::string filename, int quality, std::string ip) {
        if(img.data == nullptr){
            printf("save image error, img data is null \n");
            return;
        }

        Img img_;
        img_.w = img.w;
        img_.h = img.h;
        img_.c = img.c;
        img_.w_stride = img.w_stride;
        img_.data = img.data;
        
        // 1. 保存图片到本地
        stbi_write_jpg(filename.c_str(), img_.w, img_.h, img_.c, img_.data, quality);
        std::cout << "Saving image to: " << filename << std::endl;

        if(!ip.empty()) {
            // 2. 构造 TFTP 上传命令
            std::string tftpCmd = "tftp -p -l " + filename + " " +ip;
            std::cout << "Executing: " << tftpCmd << std::endl;

            // 3. 执行 TFTP 上传
            int result = system(tftpCmd.c_str());
            if (result != 0) {
                std::cerr << "TFTP upload failed with error code: " << result << std::endl;
            }
        }

    }

    void ImageUtils::saveFrameInfo(FrameInfo rgb_info, std::string filename, int quality, std::string ip) {
        Img img_;
        img_.w = rgb_info.width;
        img_.h = rgb_info.height;
        img_.c = 4;
        img_.w_stride = rgb_info.width * 4;
        img_.data = rgb_info.data;
        
        // 1. 保存图片到本地
        stbi_write_jpg(filename.c_str(), img_.w, img_.h, img_.c, img_.data, quality);
        std::cout << "Saving image to: " << filename << std::endl;

        if(!ip.empty()) {
            // 2. 构造 TFTP 上传命令
            std::string tftpCmd = "tftp -p -l " + filename + " " +ip;
            std::cout << "Executing: " << tftpCmd << std::endl;

            // 3. 执行 TFTP 上传
            int result = system(tftpCmd.c_str());
            if (result != 0) {
                std::cerr << "TFTP upload failed with error code: " << result << std::endl;
            }
        }

    }


    void ImageUtils::draw_boxes(MyImg &img, const std::vector<magik::uranus::ObjBbox_t> &boxes){
        if(img.data == nullptr){
            printf("draw boxes error, img data is null \n");
            return;
        }
        Img img_;
        img_.w = img.w;
        img_.h = img.h;
        img_.c = img.c;
        img_.w_stride = img.w_stride;
        img_.data = img.data;
        
        for (auto box : boxes) {
            Point pt1 = {
                .x = (int)box.box.x0,
                .y = (int)box.box.y0};
            Point pt2 = {
                .x = (int)box.box.x1,
                .y = (int)box.box.y1};
            sample_draw_box_for_image(&img_, pt1, pt2, color, 1.5);
        }
    }

    void ImageUtils::print_memory_usage_mb(const std::string& tag) {
        std::ifstream meminfo("/proc/meminfo");
        std::string line;
        long mem_total = 0, mem_free = 0, buffers = 0, cached = 0;

        // 从 /proc/meminfo 中提取关键字段（单位KB）
        while (std::getline(meminfo, line)) {
            if (line.find("MemTotal:") == 0) {
                sscanf(line.c_str(), "MemTotal: %ld kB", &mem_total);
            } else if (line.find("MemFree:") == 0) {
                sscanf(line.c_str(), "MemFree: %ld kB", &mem_free);
            } else if (line.find("Buffers:") == 0) {
                sscanf(line.c_str(), "Buffers: %ld kB", &buffers);
            } else if (line.find("Cached:") == 0) {
                sscanf(line.c_str(), "Cached: %ld kB", &cached);
            }
        }

        // 转换为MB并打印
        std::cout << "===== Memory Usage [" << tag << "] (MB) =====" << std::endl;
        // std::cout << "Total RAM: " << mem_total / 1024 << " MB" << std::endl;
        // std::cout << "Free RAM: " << mem_free / 1024 << " MB" << std::endl;
        // std::cout << "Buffers: " << buffers / 1024 << " MB" << std::endl;
        // std::cout << "Cached: " << cached / 1024 << " MB" << std::endl;
        std::cout << "Available (Free + Buffers + Cached): " 
                << (mem_free + buffers + cached) / 1024 << " MB" << std::endl;
        std::cout << "=========================================" << std::endl;
    }

    void ImageUtils::crop_image(const MyImg& in_img, const magik::uranus::Box_t& box, MyImg& out_img) {
        if(in_img.data == nullptr){
            printf("crop image error, in_img data is null \n");
            return;
        }
        // 1. 边界检查（手动实现）
        int x0 = (int)box.x0;
        int y0 = (int)box.y0;
        int x1 = (int)box.x1;
        int y1 = (int)box.y1;

        // 确保坐标不越界
        x0 = (x0 < 0) ? 0 : (x0 >= in_img.w ? in_img.w - 1 : x0);
        y0 = (y0 < 0) ? 0 : (y0 >= in_img.h ? in_img.h - 1 : y0);
        x1 = (x1 < 0) ? 0 : (x1 >= in_img.w ? in_img.w - 1 : x1);
        y1 = (y1 < 0) ? 0 : (y1 >= in_img.h ? in_img.h - 1 : y1);

        // 确保 x1 > x0 且 y1 > y0
        if (x1 <= x0 || y1 <= y0) {
            out_img.w = out_img.h = out_img.c = 0;
            out_img.data = nullptr;
            printf("crop box error \n");
            return;
        }

        // 2. 计算裁剪区域
        int crop_w = x1 - x0;
        int crop_h = y1 - y0;
        out_img.w = crop_w;
        out_img.h = crop_h;
        out_img.c = in_img.c;
        out_img.w_stride = crop_w * in_img.c;
        out_img.data = (uint8_t*)malloc(crop_h * out_img.w_stride);

        if (!out_img.data) {
            fprintf(stderr, "Memory allocation failed for %d bytes\n", crop_h * out_img.w_stride);
            return;
        }
        
        // 3. 逐行复制像素
        for (int y = 0; y < crop_h; ++y) {
            for (int x = 0; x < crop_w; ++x) {
                int src_pos = (y0 + y) * in_img.w_stride + (x0 + x) * in_img.c;
                int dst_pos = y * out_img.w_stride + x * in_img.c;
                memcpy(out_img.data + dst_pos, in_img.data + src_pos, in_img.c);
            }
        }
    }

    void ImageUtils::free_stb_mem(uint8_t* data){
        if (data) {
            stbi_image_free(data);
        }
    }


    void ImageUtils::resize_image(const MyImg& src_img, MyImg& dst_img, int dst_width, int dst_height) {
        if(src_img.data == nullptr){
            printf("resize image error, src_img data is null \n");
            return;
        }
        // 清空输出结构体
        memset(&dst_img, 0, sizeof(MyImg));
        
        if (!src_img.data || dst_width <= 0 || dst_height <= 0) {
            fprintf(stderr, "Invalid resize parameters\n");
            return;
        }

        // 初始化输出图像结构
        dst_img.w = dst_width;
        dst_img.h = dst_height;
        dst_img.c = src_img.c;
        dst_img.w_stride = dst_width * src_img.c;
        dst_img.data = (uint8_t*)malloc(dst_height * dst_img.w_stride);
        
        if (!dst_img.data) {
            fprintf(stderr, "Memory allocation failed for %d bytes\n", 
                    dst_height * dst_img.w_stride);
            return;
        }

        // 调用stb_image_resize进行缩放
        stbir_resize(
            src_img.data, src_img.w, src_img.h, src_img.w_stride,
            dst_img.data, dst_width, dst_height, dst_img.w_stride,
            STBIR_TYPE_UINT8, src_img.c,
            (src_img.c == 4) ? STBIR_ALPHA_CHANNEL_NONE : 0,
            STBIR_FLAG_ALPHA_PREMULTIPLIED,
            STBIR_EDGE_REFLECT, STBIR_EDGE_REFLECT,
            STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
            STBIR_COLORSPACE_SRGB, NULL
        );
    }

    int ImageUtils::img_to_tensor(const MyImg& src_img, magik::uranus::Tensor& dist_tensor, 
                                    int dst_width, int dst_height) {
        
        
        // 参数校验
        if (!src_img.data || src_img.c != 3 || 
            dst_width <= 0 || dst_height <= 0) {
            fprintf(stderr, "Invalid input parameters\n");
            return -1;
        }
        MyImg dist_img;
        FrameInfo dist_info;
        resize_image(src_img, dist_img, dst_width, dst_height); 
        img_to_frame(dist_img, dist_info);
        frametoTensor(dist_info, dist_tensor);
        #if 0
        // 直接分配目标Tensor内存（NHWC格式）
        magik::uranus::shape_t shape = {1, dst_height, dst_width, 4};  // 批大小=1, 4通道RGBA
        out.reshape(shape);  // 由Tensor内部管理内存
        
        uint8_t* tensor_data = out.mudata<uint8_t>();
        if (!tensor_data) {
            fprintf(stderr, "Tensor memory allocation failed\n");
            return -1;
        }

        // 单次内存分配：临时存放缩放后的3通道图像
        const size_t rgb_size = dst_width * dst_height * 3;
        uint8_t* resized_rgb = (uint8_t*)malloc(rgb_size);
        if (!resized_rgb) {
            fprintf(stderr, "Failed to allocate %zu bytes for RGB buffer\n", rgb_size);
            return -1;
        }

        // 单步缩放：直接缩放到目标尺寸(3通道)
        stbir_resize(
            src_img.data, src_img.w, src_img.h, src_img.w_stride,
            resized_rgb, dst_width, dst_height, dst_width * 3,
            STBIR_TYPE_UINT8, 3, 0, STBIR_FLAG_ALPHA_PREMULTIPLIED,
            STBIR_EDGE_REFLECT, STBIR_EDGE_REFLECT,
            STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
            STBIR_COLORSPACE_SRGB, nullptr
        );

        // 边转换边填充Alpha通道
        const size_t total_pixels = dst_width * dst_height;
        // #pragma omp parallel for  // 可选：OpenMP加速
        for (size_t i = 0; i < total_pixels; ++i) {
            const size_t src_pos = i * 3;
            const size_t dst_pos = i * 4;
            
            // 拷贝RGB并设置Alpha
            tensor_data[dst_pos + 0] = resized_rgb[src_pos + 0];  // R
            tensor_data[dst_pos + 1] = resized_rgb[src_pos + 1];  // G
            tensor_data[dst_pos + 2] = resized_rgb[src_pos + 2];  // B
            tensor_data[dst_pos + 3] = 255;                       // A
        }

        free(resized_rgb);  // 释放临时RGB缓存

        // 可选：内存对齐检查
        if (IS_ALIGN_64(tensor_data) != 0) {
            fprintf(stderr, "Warning: Tensor data address not 64-byte aligned\n");
        }
        #endif
        return 0;
    }

    void ImageUtils::frametoTensor(FrameInfo &in, magik::uranus::Tensor &out) {
        if(in.data == nullptr){
            printf("resize image error, src_img data is null \n");
            return;
        }
        // 获取输入尺寸
        int in_w = in.width;
        int in_h = in.height;
        printf("perpare_data, in_h in_w %d %d\n", in.height, in.width);

        // 强制转换为 NHWC 格式 (假设输入是 RGBA/UINT8)
        // magik::uranus::shape_t out_shape = {1, in_h, in_w, 4}; // NHWC布局
        // out.reshape(out_shape); // 调整输出Tensor形状

        // 直接拷贝数据到输出Tensor
        uint8_t* out_data = out.mudata<uint8_t>();
        memcpy((void *)out_data, (void *)in.data, out.get_bytes_size()); // 假设in.data是连续RGBA数据

        // 检查内存对齐（可选）
        if (IS_ALIGN_64(out_data) != 0) {
            fprintf(stderr, "Warning: output address not 64-byte aligned\n");
        }
    }

    void ImageUtils::prepare_data(FrameInfo &in, 
        magik::uranus::Tensor &out, 
        magik::uranus::Box_t tmp_box, 
        int input_w, 
        int input_h,
        magik::uranus::ChannelLayout image_format) {
        using namespace magik::uranus;
        using namespace std;
        int in_w = in.width;
        int in_h = in.height;
        printf("perpare_data, in_h in_w %d %d\n", in.height, in.width);
        magik::uranus::shape_t in_shape;
        magik::uranus::DataFormat data_format;
        if (image_format == magik::uranus::ChannelLayout::NV12) {
            in_shape = {1, in_h, in_w, 1};
            data_format = magik::uranus::DataFormat::NV12;
            
        } else {
            in_shape = {1, in_h, in_w, 4};
            data_format = magik::uranus::DataFormat::NHWC;
        }
        
        auto in_tensor = magik::uranus::Tensor(in_shape, magik::uranus::DataType::UINT8, data_format);
        uint8_t *in_tensor_data = in_tensor.mudata<uint8_t>();
        memcpy((void *)in_tensor_data, (void *)in.data, in_tensor.get_bytes_size());

        // resize
        magik::uranus::BsCommonParam param;
        param.pad_val = 114;
        param.pad_type = magik::uranus::BsPadType::SYMMETRY;
        param.in_layout = image_format;
        param.out_layout = magik::uranus::ChannelLayout::RGBA;
        param.input_height = in_h;
        param.input_width = in_w;
        param.input_line_stride = (image_format == magik::uranus::ChannelLayout::NV12) ? in_w : in_w * 4;
        param.addr_attr.vir_addr = in_tensor_data;
        vector<magik::uranus::Box_t> output_tmp;
        // magik::uranus::Box_t tmp_box{0, 0, static_cast<float>(in_w), static_cast<float>(in_h)};
        output_tmp.push_back(tmp_box);
        printf("work_h:%d work_w:%d \n", input_h, input_w);
        out.reshape({1, input_h, input_w, 4});
        uint8_t *out_data = out.mudata<uint8_t>();
        vector<magik::uranus::Tensor> output_tesnor;
        output_tesnor.push_back(out);
        magik::uranus::crop_common_resize(output_tesnor, output_tmp, magik::uranus::AddressLocate::NMEM_VIRTUAL, &param);
        in_tensor.free_data();

        if (IS_ALIGN_64(in_tensor_data) != 0) {
            fprintf(stderr, "input addr not align to 128 bytes.\n");
            return ;
        }
    }
}